package com.lantu.interceptor;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lantu.annotation.NotLogin;
import com.lantu.constant.CommonConstants;
import com.lantu.constant.RedisKeyConstants;
import com.lantu.core.entity.User;
import com.lantu.core.service.IUserService;
import com.lantu.utils.JwtUtils;
import com.lantu.utils.RedisUtil;
import io.jsonwebtoken.Claims;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * @author qing
 */
@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
    private final JwtUtils jwtUtils;

    private final RedisUtil redisUtil;

    private final IUserService userService;


    public AuthorizationInterceptor(JwtUtils jwtUtils, RedisUtil redisUtil, IUserService userService) {
        this.jwtUtils = jwtUtils;
        this.redisUtil = redisUtil;
        this.userService = userService;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        // 是否不需要登录
        NotLogin annotation;
        PermitAll permitAll;
        if (handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(NotLogin.class);
            permitAll = ((HandlerMethod) handler).getMethodAnnotation(PermitAll.class);
        } else {
            return true;
        }

        if (annotation != null || permitAll != null) {
            return true;
        }

        //获取用户凭证
        String token = request.getHeader(jwtUtils.getHeader());
        if (StrUtil.isBlank(token)) {
            token = request.getParameter(jwtUtils.getHeader());
        }

        //凭证为空
        if (StrUtil.isBlank(token)) {
            // 设置响应内容类型为 JSON
            response.setContentType(CommonConstants.RESPONSE_CONTENT_TYPE);
            // 构建一个 JSON 格式的错误响应
            String errorMessage = "{\"message\": \"验证失败，请重新登录！\", \"code\": \"510\"}";
            // 将 JSON 写入响应
            response.getWriter().write(errorMessage);
            response.getWriter().flush();
            return false;
        }

        Claims claims = jwtUtils.getClaimByToken(token);
        if (claims == null || jwtUtils.isTokenExpired(claims.getExpiration())) {
            // 设置响应内容类型为 JSON
            response.setContentType(CommonConstants.RESPONSE_CONTENT_TYPE);
            // 构建一个 JSON 格式的错误响应
            String errorMessage = "{\"message\": \"登录失效，请重新登录！\", \"code\": \"510\"}";
            // 将 JSON 写入响应
            response.getWriter().write(errorMessage);
            response.getWriter().flush();
            return false;
        }
        String userId = claims.getSubject();
        // 缓存中是否存在token
        boolean verified = redisUtil.hasKey(RedisKeyConstants.USER_TOKEN + token);
        if (!verified) {
            // 设置响应内容类型为 JSON
            response.setContentType(CommonConstants.RESPONSE_CONTENT_TYPE);
            // 构建一个 JSON 格式的错误响应
            String errorMessage = "{\"message\": \"登录失效，请重新登录！\", \"code\": \"510\"}";
            // 将 JSON 写入响应
            response.getWriter().write(errorMessage);
            response.getWriter().flush();
            return false;
        }

        //检验用户是否有效
        User loginUser = userService.getById(userId);
        if(ObjectUtil.isNull(loginUser) || StrUtil.isEmpty(loginUser.getId()) || !ObjectUtil.equals(loginUser.getStatus(), CommonConstants.USER_NORMAL_STATUS)){
            // 设置响应内容类型为 JSON
            response.setContentType(CommonConstants.RESPONSE_CONTENT_TYPE);
            // 构建一个 JSON 格式的错误响应
            String errorMessage = "{\"message\": \"登录信息异常，请重新登录！\"}";
            // 将 JSON 写入响应
            response.getWriter().write(errorMessage);
            response.getWriter().flush();
            return false;
        }

        // 设置userId到request里，后续根据userId，获取用户信息
        request.setAttribute(CommonConstants.USER_KEY, userId);
        // 不允许访问
//        if (StringUtils.containsAny(request.getRequestURI(), "/mange/", "/system/env/")) {
//            if (!SecurityUtils.isAdmin(userId)) {
//                throw new AuthorizationException("无权限访问");
//            }
//        }
        return true;
    }
}
